﻿# define _CRT_SECURE_NO_WARNINGS 1

#include <string.h>
#include <stdio.h>

//int main()
//{
//	//char arr[] = "abcdef";//[a b c d e f \0]
//	char arr[] = { 'a', 'b', 'c' ,'\0'};//[a b c]
//	size_t len = strlen(arr);
//	printf("%zd\n", len);
//
//	return 0;
//}

//int main()
//{
//	//3-6=-3
//	if ((int)strlen("abc") - (int)strlen("abcdef") > 0)
//	{
//		printf("大于\n");
//	}
//	else
//	{
//		printf("小于等于\n");
//	}
//	return 0;
//}
//

3. strlen的使⽤和模拟实现
• 字符串以 '\0' 作为结束标志，strlen函数返回的是在字符串中 '\0' 前⾯出现的字符个数（不包
含 '\0' )。
• 参数指向的字符串必须要以 '\0' 结束。
• 注意函数的返回值为size_t，是⽆符号的（ 易错 ）
• strlen的使⽤需要包含头⽂件
• 学会strlen函数的模拟实现
#include <assert.h>
⽅式1：

size_t my_strlen1(const char* str)
{
	size_t count = 0;
	assert(str != NULL);
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}

size_t my_strlen2(const char* str)
{
	assert(str);
	const char* start = str;
	while (*str)
	{
		str++;
	}
	return str - start;
}

//写一个函数，不能使用临时变量，求字符串长度 - 递归
size_t my_strlen(const char* str)
{
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}

//my_strlen("abcdef");
//1+my_strlen("bcdef");
//1+1+my_strlen("cdef");
//1+1+1+my_strlen("def");
//1+1+1+1+my_strlen("ef");
//1+1+1+1+1+my_strlen("f");
//1+1+1+1+1+1+my_strlen("");
//1+1+1+1+1+1+0;
//
//int main()
//{
//	char arr[] = "abc";
//	size_t len = my_strlen(arr);
//	printf("%zd\n", len);
//
//	return 0;
//}
//

4. strcpy 的使⽤和模拟实现
Copies the C string pointed by source into the array pointed by destination, including the
terminating null character(and stopping at that point).
• 源字符串必须以 '\0' 结束。
• 会将源字符串中的 '\0' 拷⻉到⽬标空间。
• ⽬标空间必须⾜够⼤，以确保能存放源字符串。
• ⽬标空间必须可修改。
• 学会模拟实现。
//int main()
//{
//	char arr1[20] = "xxxxxxxxx";
//	char arr2[] = {'a', 'b', 'c','\0'};
//	strcpy(arr1, arr2);
//	printf("%s\n", arr1);
//
//	return 0;
//}

//int main()
//{
//	char arr1[5] = {0};//目标空间必须足够大
//	char arr2[] = "hello world";
//	strcpy(arr1, arr2);
//	printf("%s\n", arr1);
//
//	return 0;
//}

//int main()
//{
//	char* p = "abcdefghilmkqwer";//常量字符串，不能修改
//	char arr2[] = "hello world";
//	strcpy(p, arr2);//目标空间必须是可修改的
//	printf("%s\n", p);
//
//	return 0;
//}

//模拟实现strcpy函数

char* my_strncpy(char* dest, const char* src, size_t n)
{
	assert(dest);//利用断言需要使用头文件#include<assert.h>
	assert(src);
	char* destPtr = dest;//定义dest和src的指针变量destPtr和srcPtr,用于遍历字符串。
	const char* srcPtr = src;

	while (n-- > 0) //使用while循环遍历n个字符
	{
		if (*srcPtr != '\0')  //检查当前源字符串srcPtr指向的字符是否为'\0'结束符
		{
			*destPtr++ = *srcPtr++;//如果不是结束符，就将源字符串当前字符复制到目标字符串，
		}										//并同时将两个指针前移到下一个字符。
		else //如果是结束符，进入else块
		{
			*destPtr++ = '\0';//将目标字符串当前字符设置为结束符'\0'
		}							  //然后destPtr再++
	}

	return dest; //返回目标字符串首地址。
}




// 
// 
//char* my_strncpy(char* str1, const char* str2, size_t n)
//{
//	size_t i;
//
//	for (i = 0; i < n && str2[i] != '\0'; i++)
//	{
//		str1[i] = str2[i];
//	}
//
//	// 当源字符串长度小于n时，用'\0'填充剩余字符
//	while (i < n)
//	{
//		str1[i++] = '\0';
//	}
//
//	return str1;
//
//}
//
//int main()
//{
//	char dest[20] = "xxxxxxxxxxxxxxxxx";
//	char src[] = "hello";
//
//	my_strncpy(dest, src, 10);
//
//	printf("%s\n", dest);
//
//	return 0;
//
//}




5. strcat 的使⽤和模拟实现
源字符串必须以 '\0' 结束。
• ⽬标字符串中也得有 \0 ，否则没办法知道追加从哪⾥开始。
• ⽬标空间必须有⾜够的⼤，能容纳下源字符串的内容。
• ⽬标空间必须可修改。
• 字符串⾃⼰给⾃⼰追加，如何？
//char* my_strcat(char* dest, const char* src)
//{
//	char* ret = dest;
//	assert(dest && src);
//	//1. 找到目标空间的\0
//	while (*dest)
//	{
//		dest++;
//	}
//	//2. 拷贝
//	while (*dest++ = *src++)
//	{
//		;
//	}
//
//	return ret;
//}
//
//int main()
//{
//	char arr1[20] = "hello ";
//	char arr2[] = "world";
//	my_strcat(arr1, arr2);
//	printf("%s\n", arr1);
//
//	return 0;
//}

//char* my_strcat(char* dest, const char* src)
//{
//	char* ret = dest;
//	assert(dest && src);
//	//1. 找到目标空间的\0
//	while (*dest)
//	{
//		dest++;
//	}
//	//2. 拷贝
//	while (*dest++ = *src++)
//	{
//		;
//	}
//
//	return ret;
//}
//
//int main()
//{
//	char arr1[20] = "hello ";
//	my_strcat(arr1, arr1);
//	printf("%s\n", arr1);
//
//	return 0;
//}
//
//char* my_strncat(char* dest, const char* src, size_t n) {
//
//	//参数检查
//	if (dest == NULL || src == NULL) {
//		return NULL;
//	}
//
//	char* ptr = dest;
//
//	//找到目标字符串结尾
//	while (*dest != '\0') {
//		dest++;
//	}
//
//	//复制源字符串的前n个字符
//	while (n > 0 && *src != '\0') {
//		if (n == 1) {
//			break;
//		}
//		*dest++ = *src++;
//		n--;
//	}
//
//	//添加字符串结束符
//	*dest = '\0';
//
//	return ptr;
//}
//
//int main() {
//
//	char str1[100] = "hello";
//	char str2[100] = " world";
//
//	my_strncat(str1, str2, 6);
//	printf("%s\n", str1);
//
//	return 0;
//}

char* my_strncat(char* dst, const char* src, size_t n)
{
	char* tmp = dst;

	while (*dst)//使用while循环遍历dst字符串。
	{
		dst++;//找到字符串结束位置'\0'。
	}

	int i;
	for (i = 0; src[i] && i < n; i++)//  i < n 判断是否超过最大复制长度n
	{											 //src[i] 判断源字符串是否结束
		dst[i] = src[i];
	}

	dst[i] = 0;//在目标字符串末尾添加字符串结束标记'\0'。
	return tmp;
}

6. strcmp 的使⽤和模拟实现
标准规定：
◦ 第⼀个字符串⼤于第⼆个字符串，则返回⼤于0的数字
◦ 第⼀个字符串等于第⼆个字符串，则返回0
◦ 第⼀个字符串⼩于第⼆个字符串，则返回⼩于0的数字
◦ 那么如何判断两个字符串？ ⽐较两个字符串中对应位置上字符ASCII码值的⼤⼩
//int main()
//{
//	int ret = strcmp("bbq", "abcdef");
//	printf("%d\n", ret);
//
//	return 0;
//}


//int main()
//{
//	int ret = strcmp("bbq", "abcdef");
//	if (ret > 0)
//		printf("大于\n");
//	else if (ret == 0)
//		printf("等于\n");
//	else
//		printf("小于\n");
//
//	return 0;
//}

//int my_strcmp(const char* s1, const char* s2)
//{
//	while (*s1 == *s2)
//	{
//		if (*s1 == '\0')
//			return 0;
//		s1++;
//		s2++;
//	}
//	if (*s1 > *s2)
//		return 1;
//	else
//		return -1;
//}
//
//int my_strcmp(const char* s1, const char* s2)
//{
//	while (*s1 == *s2)
//	{
//		if (*s1 == '\0')
//			return 0;
//		s1++;
//		s2++;
//	}
//	return *s1 - *s2;
//}
//
//int main()
//{
//	int ret = my_strcmp("abcdef", "abc");
//	if (ret > 0)
//		printf("大于\n");
//	else if (ret == 0)
//		printf("等于\n");
//	else
//		printf("小于\n");
//	return 0;
//}
//
//





7. strncpy 函数的使⽤
• 拷⻉num个字符从源字符串到⽬标空间。
• 如果源字符串的⻓度⼩于num，则拷⻉完源字符串之后，在⽬标的后边追加0，直到num个

//int main()
//{
//	char arr1[20] = "xxxxxxxxxx";
//	char arr2[] = "hello";
//	strncpy(arr1, arr2, 7);
//
//	return 0;
//}

#include <stdio.h>
#include <string.h>
#include <assert.h>


char* my_strncpy(char* dest, const char* src, int n)
{
	assert(dest != NULL);
	assert(src != NULL);
	char* orig_dest = dest;
	while (n-- > 0 && *src != 0)
	{
		*dest++ = *src++;
	}
	*dest = '\0';

	while (n-- > 0)
	{
		*dest++ = '\0';
	}

	return orig_dest;
}

int main()
{
	int input = 0;
	char arr1[100];
	char arr2[] = "abcdef";
	while (scanf("%d", &input) != EOF)
	{
		char* ret = my_strncpy(arr1, arr2, input);

		if (ret == NULL)
		{
			printf("Destination is invalid\n");
			return 1;
		}
		else
		{
			printf("%s\n", ret);

		}
	}
	return 0;
}




8. strncat 函数的使⽤
//int main()
//{
//	char arr1[20] = "hello\0xxxxxxxxxxx";
//	char arr2[] = "world";
//	strncat(arr1, arr2, 7);
//
//	return 0;
//}

#include <stdio.h>
#include <string.h>
#include <assert.h>

char* my_strncat(char* dest, const char* src, size_t n)
{
	char* orig_dest = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (*dest)
	{
		dest++;
	}
	while (n-- > 0 && *src != '\0')
	{
		*dest++ = *src++;
	}

	*dest = '\0';
	return orig_dest;
}

int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	printf("%s\n", arr1);
	char* ret = my_strncat(arr1, arr2, 6);
	printf("%s\n", ret);
	return 0;
}


9. strncmp函数的使⽤


//int main()
//{
//	char arr1[] = "abcdef";
//	char arr2[] = "abcq";
//	int ret = strncmp(arr1, arr2, 3);
//
//	printf("%d\n", ret);
//	return 0;
//}

int my_strncmp(const char* s1, const char* s2, size_t n)
{
	int i = 0;
	//这是一个 for 循环，用于迭代比较两个字符串中的字符。
	for (; i < n && s1[i] != '\0' && s2[i] != '\0'; i++)
	{
		if (s1[i] != s2[i])
		{
			return s1[i] - s2[i];//如果当前位置的两个字符不相等，返回它们的差值。
		}
	}

	if (i <= n)
	{
		return s1[i] - s2[i];//如果 i 小于等于 n，但是循环结束了（即至少一个字符串已经达到结束符 ‘\0’），则返回当前位置字符的差值。
	}

	return 0;
}
int main()
{
	char s1[] = "hello";
	char s2[] = "helloworld";

	int result = my_strncmp(s1, s2, 5);

	printf("result = %d\n", result);

	return 0;
}
10. strstr 的使⽤和模拟实现
//strstr 返回字符串在另外一个字符中第一次出现的位置
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
（函数返回字符串str2在字符串str1中第⼀次出现的位置）。
The matching process does not include the terminating null - characters, but it stops there.（字符
串的⽐较匹配不包含 \0 字符，以 \0 作为结束标志）。
//int main()
//{
//	char arr1[] = "abcdefabcdef";
//	char arr2[] = "deq";
//	char* ret = strstr(arr1, arr2);
//	if (ret != NULL)
//		printf("%s\n", ret);
//	else
//		printf("找不到\n");
//
//	return 0;
//}

char* my_strstr(const char* str1, const char* str2)
{
	const char* cur = str1;
	const char* s1 = NULL;
	const char* s2 = NULL;

	assert(str1 && str2);
	if (*str2 == '\0')
	{
		return (char*)str1;
	}

	while (*cur)
	{
		s1 = cur;
		s2 = str2;
		while (*s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)cur;
		}
		cur++;
	}
	return NULL;
}

int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbq";
	char* ret = my_strstr(arr1, arr2);
	if (ret != NULL)
		printf("%s\n", ret);
	else
		printf("找不到\n");

	return 0;
}




